



#include "mcu_soft_iic.h"



/// <summary>
/// iic scl 引脚设置高电平
/// </summary>
/// <param name="device">IIC 设备</param>
void IIC_SCL_H(IICdevice* device) {	mcu_set_io(device->scl, 1); }
/// <summary>
/// iic scl 引脚设置低电平
/// </summary>
/// <param name="device">IIC 设备</param>
void IIC_SCL_L(IICdevice* device) { mcu_set_io(device->scl, 0); }
/// <summary>
/// iic sda 引脚设置高电平
/// </summary>
/// <param name="device">IIC 设备</param>
void IIC_SDA_H(IICdevice* device) { mcu_set_io(device->sda, 1); }
/// <summary>
/// iic sda 引脚设置低电平
/// </summary>
/// <param name="device">IIC 设备</param>
void IIC_SDA_L(IICdevice* device) { mcu_set_io(device->sda, 0); }
/// <summary>
/// 读取iic sda 引脚电平
/// </summary>
/// <param name="device">IIC 设备</param>
/// <returns>0低电平，1高电平</returns>
int IIC_SDA_READ(IICdevice* device) { return mcu_read_io(device->sda); }

/// <summary>
/// SDA引脚设置输出模式
/// </summary>
/// <param name="device">IIC 设备</param>
void Soft_IIC_Output(IICdevice* device) { mcu_set_io_out(device->sda); }

/// <summary>
/// SDA引脚设置输入模式
/// </summary>
/// <param name="device">IIC 设备</param>
void Soft_IIC_Input(IICdevice* device) { mcu_set_io_in(device->sda); }
//






#define IIC_DELAY_TIME 10 //延时倍数


//

// 上面是硬件部分。

/**
 * @brief IIC延时
 * @param  无
 * @return 无
 */
void IIC_Delay(int time)
{
	unsigned int i = time * 1; // 用户根据自己的MCU时钟进行设置倍数
	while (i--)
	{
		;
	}
}


/**
 * @brief IIC初始化
 * @param  无
 * @return 无
 */
void Soft_IIC_Init(IICdevice* device)
{
	Soft_IIC_Output(device);
	IIC_SDA_H(device);
	IIC_SCL_H(device);
}


/**
 * @brief IIC起始信号
 * @param  无
 * @return 无
 */
void Soft_IIC_Start(IICdevice* device)
{
	Soft_IIC_Output(device);
	IIC_SCL_L(device);
	IIC_SDA_H(device);
	IIC_SCL_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SDA_L(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_L(device);
}

/**
 * @brief IIC停止信号
 * @param  无
 * @return 无
 */
void Soft_IIC_Stop(IICdevice* device)
{
	Soft_IIC_Output(device);
	IIC_SCL_L(device);
	IIC_SDA_L(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SDA_H(device);
	IIC_Delay(IIC_DELAY_TIME);
}

/**
 * @brief IIC应答信号
 * @param  无
 * @return 无
 */
void Soft_IIC_ACK(IICdevice* device)
{
	Soft_IIC_Output(device);
	IIC_SCL_L(device);
	IIC_Delay(IIC_DELAY_TIME / 2);
	IIC_SDA_L(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_L(device);
	IIC_Delay(IIC_DELAY_TIME / 2);
}

/**
 * @brief IIC无应答信号
 * @param  无
 * @return 无
 */
void Soft_IIC_NACK(IICdevice* device)
{
	Soft_IIC_Output(device);
	IIC_SCL_L(device);
	IIC_Delay(IIC_DELAY_TIME / 2);
	IIC_SDA_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_H(device);
	IIC_Delay(IIC_DELAY_TIME / 2);
	//    IIC_SCL_L(device);
}

/**
 * @brief IIC等待应答信号
 * @param  无
 * @return 0无应答  1有应答
 */
ACK_STATUS Soft_IIC_Wait_ACK(IICdevice* device)
{
	unt8 wait = 0;
	Soft_IIC_Output(device);
	IIC_SDA_H(device);
	IIC_Delay(IIC_DELAY_TIME / 2);

	Soft_IIC_Input(device);
	IIC_SCL_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	while (IIC_SDA_READ(device))
	{
		wait++;
		IIC_Delay(IIC_DELAY_TIME);
		if (wait > 250)
		{
			Soft_IIC_Stop(device);
			return NACK;
		}
	}
	IIC_SCL_L(device);
	IIC_Delay(IIC_DELAY_TIME);
	return ACK;
}

/**
 * @brief IIC写数据1
 * @param  无
 * @return 无
 */
void Soft_IIC_Write_High(IICdevice* device)
{
	IIC_SCL_L(device);
	IIC_Delay(IIC_DELAY_TIME / 2);
	IIC_SDA_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_L(device);
}

/**
 * @brief IIC写数据0
 * @param  无
 * @return 无
 */
void Soft_IIC_Write_Low(IICdevice* device)
{
	IIC_SCL_L(device);
	IIC_Delay(IIC_DELAY_TIME / 2);
	IIC_SDA_L(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_H(device);
	IIC_Delay(IIC_DELAY_TIME);
	IIC_SCL_L(device);
}

/**
 * @brief IIC写入单个数据
 * @param  无
 * @return 应答信号, 0无应答 1有应答
 */
ACK_STATUS Soft_IIC_Send_Byte(IICdevice* device, unt8 Byte)
{
	unt8 i;
	Soft_IIC_Output(device);
	for (i = 0x80; i != 0; i >>= 1)
	{
		if (Byte & i)
		{
			Soft_IIC_Write_High(device);
		}
		else
		{
			Soft_IIC_Write_Low(device);
		}
	}
	return (Soft_IIC_Wait_ACK(device));
}

/**
 * @brief IIC读一个数据
 * @param  ACK:应答 NACK:不应答
 * @return 返回读到的数据
 */
unt8 Soft_IIC_Recv_Byte(IICdevice* device, ACK_STATUS ack_sta)
{
	unt8 data = 0, i;
	Soft_IIC_Input(device);

	IIC_SCL_L(device);
	IIC_Delay(IIC_DELAY_TIME);

	//    IIC_SCL_H(device);
	//    IIC_Delay(IIC_DELAY_TIME);
	for (i = 0x80; i != 0; i >>= 1)
	{
		IIC_SCL_H(device);
		IIC_Delay(IIC_DELAY_TIME);
		if (IIC_SDA_READ(device) == 1)
		{
			data |= i;
		}
		//  IIC_Delay(IIC_DELAY_TIME);
		IIC_SCL_L(device);
		IIC_Delay(IIC_DELAY_TIME);
	}
	if (ack_sta == ACK)
	{
		Soft_IIC_ACK(device);
	}
	else
	{
		Soft_IIC_NACK(device);
	}
	return data;
}
//


#define	ReadAddress(addr)	 ((addr)|0x01)	    //往地址addr读数据的指令。
#define	WriteAddress(addr)	 ((addr)&0xFE)	    //往地址addr写数据的指令。

/// <summary>
/// 向地址是IC_Address的I2C设备写入dat_Length个数据dat。如果发送成功，返回true，否则返回false。
/// </summary>
/// <param name="device"></param>
/// <param name="IC_Address">IIC设备地址</param>
/// <param name="dat">数据数组</param>
/// <param name="dat_Length">数据长度</param>
/// <returns>是否写入成功</returns>
bool Soft_IIC_Send_Bytes(IICdevice* device, unt8 IC_Address, unt8* dat, int dat_Length)
{
	int i;
	Soft_IIC_Start(device);                              //起始信号
	Soft_IIC_Send_Byte(device, WriteAddress(IC_Address));   //发送设备地址+写信号
	for (i = 0; i < dat_Length; i++) {
		if (Soft_IIC_Send_Byte(device, dat[i]) == NACK) {  //如果对方不应答，说明发送数据失败了。
			return 0;
		}
	}
	Soft_IIC_Stop(device);                                //发送停止信号
	return 1;
}

/// <summary>
/// 从地址是IC_Address的I2C设备读取dat_Length个数据dat。如果读取成功，返回true，否则返回false。
/// </summary>
/// <param name="device"></param>
/// <param name="IC_Address">IIC设备地址</param>
/// <param name="dat">数据数组</param>
/// <param name="dat_Length">数据长度</param>
/// <returns>是否读取成功</returns>
bool Soft_IIC_Recv_Bytes(IICdevice* device, unt8 IC_Address, unt8* dat, int dat_Length)
{
	int i;
	ACK_STATUS er = NACK;
	Soft_IIC_Start(device);                                 //起始信号
	er = Soft_IIC_Send_Byte(device, ReadAddress(IC_Address));       //发送设备地址+写信号
	for (i = 0; i < dat_Length - 1; i++) {
		dat[i] = Soft_IIC_Recv_Byte(device, ACK);
	}
	dat[dat_Length - 1] = Soft_IIC_Recv_Byte(device, NACK);    //最后一个字节不应答
	Soft_IIC_Stop(device);                                   //发送停止信号
	return (er == ACK); 
}
//


/// <summary>
/// 往IIC设备地址是IC_Address的器件写入数据，设备寄存器地址是addr，地址长度是1或2，（8位地址或16位地址）
/// 写入数据是buf[],数组长度是buf_len
/// </summary>
/// <param name="IC_Address">IIC设备地址</param>
/// <param name="addr">寄存器地址</param>
/// <param name="addr_len">地址长度,=1或=2</param>
/// <param name="buf">数据缓存</param>
/// <param name="buf_len">缓存长度</param>
void Soft_IIC_write(IICdevice* device, unt8 IC_Address, unt16 addr, unt8 addr_len, unt8* buf, unt16 buf_len)
{
	int i = 0;

	Soft_IIC_Start(device);
	//写器件地址
	Soft_IIC_Send_Byte(device,IC_Address);
	//写内存地址
	if (addr_len == 1)
	{
		Soft_IIC_Send_Byte(device,addr & 0xff);
	}
	else if (addr_len == 2)
	{
		Soft_IIC_Send_Byte(device,addr >> 8);
		Soft_IIC_Send_Byte(device,addr & 0xff);
	}
	//写数据
	for (i = 0; i < buf_len; i++)
	{
		Soft_IIC_Send_Byte(device,buf[i]);
	}
	Soft_IIC_Stop(device);
}

/// <summary>
/// 从IIC设备地址是IC_Address的器件读出数据，设备寄存器地址是addr，地址长度是1或2，（8位地址或16位地址）
/// 读出数据是buf[],长度是buf_len
/// </summary>
/// <param name="IC_Address">IIC设备地址</param>
/// <param name="IC_Address">IIC设备地址</param>
/// <param name="addr">寄存器地址</param>
/// <param name="addr_len">地址长度,=1或=2</param>
/// <param name="buf">数据缓存</param>
/// <param name="buf_len">缓存长度</param>
void Soft_IIC_read(IICdevice* device, unt8 IC_Address, unt16 addr, unt8 addr_len, unt8* buf, unt16 buf_len)
{
	int i = 0;
	Soft_IIC_Start(device);
	//写器件地址	
	Soft_IIC_Send_Byte(device,IC_Address);
	//写内存地址
	if (addr_len == 1)
	{
		Soft_IIC_Send_Byte(device,addr & 0xff);
	}
	else if (addr_len == 2)
	{
		Soft_IIC_Send_Byte(device,addr >> 8);
		Soft_IIC_Send_Byte(device,addr & 0xff);
	}
	//读数据
	Soft_IIC_Start(device);
	Soft_IIC_Send_Byte(device,IC_Address | 0x01);
	for (i = 0; i < buf_len - 1; i++) {
		buf[i] = Soft_IIC_Recv_Byte(device, ACK);
	}
	buf[buf_len - 1] = Soft_IIC_Recv_Byte(device, NACK);    //最后一个字节不应答

	Soft_IIC_Stop(device);
}

//



